/**
 * Created with CLion.
 * Description: 
 * User: loong
 * Date: 2024/9/6
 * Time: 22:14
 */

#include "DataHandle.h"

DataHandle::DataHandle()
{
    sql_database_ = "DataHandle";
    if(QSqlDatabase::contains(sql_database_))
        QSqlDatabase::removeDatabase(sql_database_);

    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", sql_database_);

    db.setHostName("127.0.0.1");
    db.setDatabaseName("Chat");
    db.setUserName("root");
    db.setPassword("123");

    if(!db.open())
        qDebug() << db.lastError();
}

DataHandle::~DataHandle()
{
    {
        auto db = QSqlDatabase::database(sql_database_);
        if(db.isOpen())
            db.close();
    }
    QSqlDatabase::removeDatabase(sql_database_);
}

bool DataHandle::AddUser(const UserInfoSPtr & _info)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(insert into Chat.ChatUsers(user_id, user_name) values ('%1','%2');)")
                          .arg(QString::fromStdString(_info->id))
                          .arg(QString::fromStdString(_info->name));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

bool DataHandle::RemoveUser(const std::string & _id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(delete from Chat.ChatUsers where user_id = '%1';)")
                          .arg(QString::fromStdString(_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

UserInfoSPtr DataHandle::FindUser(const std::string & _id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(select user_id,user_name from Chat.ChatUsers where user_id = '%1';)")
                          .arg(QString::fromStdString(_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return nullptr;

    UserInfoSPtr info;
    if(query.next()) {
        info       = std::make_shared<UserInfo>();
        info->id   = query.value(0).toString().toStdString();
        info->name = query.value(1).toString().toStdString();
    }

    return info;
}

bool DataHandle::AddGroup(const GroupInfoSPtr & _info)
{
    auto    db  = QSqlDatabase::database(sql_database_);
    QString sql = QString(R"(insert into Chat.ChatGroups(group_id, group_name) values ('%1','%2');)")
                          .arg(QString::fromStdString(_info->id))
                          .arg(QString::fromStdString(_info->name));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

bool DataHandle::RemoveGroup(const std::string & _id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(delete from Chat.ChatGroups where group_id = '%1';)")
                          .arg(QString::fromStdString(_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

GroupInfoVec DataHandle::FindGroupWithNameLike(const std::string & _name)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(select group_id, group_name from Chat.ChatGroups where group_name like '%%1%';)")
                          .arg(QString::fromStdString(_name));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return {};

    GroupInfoVec ret;
    while(query.next()) {
        auto info  = std::make_shared<GroupInfo>();
        info->id   = query.value(0).toString().toStdString();
        info->name = query.value(1).toString().toStdString();

        ret.push_back(info);
    }

    return ret;
}

GroupInfoVec DataHandle::FindGroupWithIDLike(const std::string & _id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(select group_id, group_name from Chat.ChatGroups where group_id like '%%1%';)")
                          .arg(QString::fromStdString(_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return {};

    GroupInfoVec ret;
    while(query.next()) {
        auto info  = std::make_shared<GroupInfo>();
        info->id   = query.value(0).toString().toStdString();
        info->name = query.value(1).toString().toStdString();

        ret.push_back(info);
    }

    return ret;
}

bool DataHandle::JoinGroup(const std::string & _group_id, const std::string & _user_id)
{
    auto db = QSqlDatabase::database(sql_database_);

    auto user = FindUser(_user_id);
    if(user == nullptr)
        return false;

    QString sql = QString(R"(insert into Chat.ChatGroupMembers(group_id, user_id, user_name, role) values ('%1','%2','%3','Normal');)")
                          .arg(QString::fromStdString(_group_id))
                          .arg(QString::fromStdString(_user_id))
                          .arg(QString::fromStdString(user->name));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

bool DataHandle::ModifyGroupMemberRole(const std::string & _group_id, const std::string & _user_id, GroupInfo::Type _type)
{
    auto db = QSqlDatabase::database(sql_database_);

    auto RoleToString = [=]() -> std::string {
        switch(_type) {
            case GroupInfo::Creator: return "Creator";
            case GroupInfo::Admin: return "Admin";
            case GroupInfo::Normal: return "Normal";
        }
    };

    QString sql = QString(R"(update Chat.ChatGroupMembers set role = '%1' where group_id = '%2' and user_id = '%3';)")
                          .arg(QString::fromStdString(RoleToString()))
                          .arg(QString::fromStdString(_group_id))
                          .arg(QString::fromStdString(_user_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

GroupInfo::Type DataHandle::UserType(const std::string & _group_id, const std::string & _user_id)
{
    auto db = QSqlDatabase::database(sql_database_);

    auto StringToRole = [=](const std::string & _type) -> GroupInfo::Type {
        if(_type == "Creator")
            return GroupInfo::Creator;
        if(_type == "Admin")
            return GroupInfo::Admin;
        if(_type == "Normal")
            return GroupInfo::Normal;
    };

    QString sql = QString(R"(select role from Chat.ChatGroupMembers where group_id = '%1' and user_id = '%2';)")
                          .arg(QString::fromStdString(_group_id))
                          .arg(QString::fromStdString(_user_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return GroupInfo::None;

    if(query.next())
        return StringToRole(query.value(0).toString().toStdString());

    return GroupInfo::None;
    ;
}

bool DataHandle::ExitGroup(const std::string & _group_id, const std::string & _user_id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(delete from Chat.ChatGroupMembers where group_id = '%1' and user_id = '%2';)")
                          .arg(QString::fromStdString(_group_id))
                          .arg(QString::fromStdString(_user_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.numRowsAffected() > 0;
}

bool DataHandle::MemberIsExist(const std::string & _group_id, const std::string & _user_id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(select user_id from Chat.ChatGroupMembers where group_id = '%1' and user_id = '%2';)")
                          .arg(QString::fromStdString(_group_id))
                          .arg(QString::fromStdString(_user_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return false;

    return query.size() > 0;
}

UserInfoVec DataHandle::Members(const std::string & _group_id)
{
    auto db = QSqlDatabase::database(sql_database_);

    QString sql = QString(R"(select user_id,user_name from Chat.ChatGroupMembers where group_id = '%1';)")
                          .arg(QString::fromStdString(_group_id));

    QSqlQuery query(db);
    if(!query.exec(sql))
        return {};

    UserInfoVec ret;
    while(query.next()) {
        auto info  = std::make_shared<UserInfo>();
        info->id   = query.value(0).toString().toStdString();
        info->name = query.value(1).toString().toStdString();

        ret.push_back(info);
    }

    return ret;
}
